﻿using System;
using System.Web;
using System.Web.Hosting;
using System.Web.Security;
using Jayden.Dll.Core.Persistence;

namespace Jayden.Dll.Core.Membership
{
	public class UserProvider : System.Web.Security.MembershipProvider
	{
		private string m_ApplicationName = "Jayden";
		private Configuration m_Configuration;

		public override string ApplicationName { get { return m_ApplicationName; } set { m_ApplicationName = value; } }

		public Configuration Configuration
		{
			get
			{
				if (m_Configuration == null)
					m_Configuration = new Configuration(HostingEnvironment.MapPath("/Configuration.xml"));
				return m_Configuration;
			}
		}
		public MaybeDisposable<UnitOfWork> UnitOfWork
		{
			get
			{
				HttpContext context = HttpContext.Current;
				if (context != null)
				{
					UnitOfWork uow = context.Items["UnitOfWork"] as UnitOfWork;
					if (uow != null)
						return new MaybeDisposable<UnitOfWork>(uow, false);
				}
				return new MaybeDisposable<UnitOfWork>(new UnitOfWork(Configuration.GetConfiguration("UnitOfWork")));
			}
		}

		public override bool ChangePassword(string username, string oldPassword, string newPassword)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(username);
				if (user != null && user.Password == oldPassword)
				{
					user.Password = newPassword;
					dataAccess.Update(user);
					return true;
				}
				return false;
			}
		}

		public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(username);
				if (user != null && user.Password == password)
				{
					user.PasswordQuestion = newPasswordQuestion;
					user.PasswordAnswer = newPasswordAnswer;
					dataAccess.Update(user);
					return true;
				}
				return false;
			}
		}

		public override System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.MembershipCreateStatus status)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				status = System.Web.Security.MembershipCreateStatus.ProviderError;
				if (providerUserKey == null)
					providerUserKey = (uint)0;

				User sameUserName = dataAccess.ReadByName(username);
				if (sameUserName != null)
				{
					status = System.Web.Security.MembershipCreateStatus.DuplicateUserName;
					return null;
				}
				User sameEmail = dataAccess.ReadByEmail(email);
				if (sameEmail != null)
				{
					status = System.Web.Security.MembershipCreateStatus.DuplicateEmail;
					return null;
				}

				User user = new User(UnitOfWork.Disposable, "Jayden", username, (uint)providerUserKey, email, passwordQuestion, string.Empty, isApproved, false, DateTime.Now, DateTime.MinValue, DateTime.Now, DateTime.Now, DateTime.MinValue);
				user.Password = password;
				user.PasswordAnswer = passwordAnswer;
				try
				{
					dataAccess.Create(user);
					status = System.Web.Security.MembershipCreateStatus.Success;
				}
				catch (Exception e)
				{
					status = System.Web.Security.MembershipCreateStatus.ProviderError;
					user = null;
				}
				return user;
			}
		}

		public override bool DeleteUser(string username, bool deleteAllRelatedData)
		{
			throw new NotImplementedException();
		}

		public override bool EnablePasswordReset { get { return true; } }
		public override bool EnablePasswordRetrieval { get { return true; } }

		public override System.Web.Security.MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			throw new NotImplementedException();
		}

		public override System.Web.Security.MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			throw new NotImplementedException();
		}

		public override System.Web.Security.MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
		{
			throw new NotImplementedException();
		}

		public override int GetNumberOfUsersOnline()
		{
			throw new NotImplementedException();
		}

		public override string GetPassword(string username, string answer)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(username);
				if (user != null && user.PasswordAnswer == answer)
					return user.Password;
				return null;
			}
		}

		public override System.Web.Security.MembershipUser GetUser(string username, bool userIsOnline)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(username);
				if (user != null && userIsOnline)
				{
					user.LastActivityDate = DateTime.Now;
					dataAccess.Update(user);
				}
				return user;
			}
		}

		public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.Read(uow.Disposable.NewObjectId(dataAccess.Entity, providerUserKey));
				if (user != null && userIsOnline)
				{
					user.LastActivityDate = DateTime.Now;
					dataAccess.Update(user);
				}
				return user;
			}
		}

		public override string GetUserNameByEmail(string email)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByEmail(email);
				if (user != null)
					return user.UserName;
				return null;
			}
		}

		public override int MaxInvalidPasswordAttempts { get { return 11; } }

		public override int MinRequiredNonAlphanumericCharacters { get { return 0; } }

		public override int MinRequiredPasswordLength { get { return 5; } }

		public override int PasswordAttemptWindow { get { return 150; } }

		public override System.Web.Security.MembershipPasswordFormat PasswordFormat { get { return System.Web.Security.MembershipPasswordFormat.Clear; } }

		public override string PasswordStrengthRegularExpression { get { return null; } }

		public override bool RequiresQuestionAndAnswer { get { return true; } }

		public override bool RequiresUniqueEmail { get { return true; } }

		public override string ResetPassword(string username, string answer)
		{
			throw new NotImplementedException();
		}

		public override bool UnlockUser(string userName)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(userName);
				if (user != null && user.IsLockedOut)
				{
					user.IsLockedOut = false;
					dataAccess.Update(user);
					return true;
				}
				return false;
			}
		}

		public override void UpdateUser(System.Web.Security.MembershipUser user)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				dataAccess.Update(user as User);
			}
		}

		public override bool ValidateUser(string username, string password)
		{
			using (MaybeDisposable<UnitOfWork> uow = UnitOfWork)
			{
				UserDataAccess dataAccess = uow.Disposable.DataAccessManager.GetDataAccess<User>() as UserDataAccess;
				User user = dataAccess.ReadByName(username);
				if (user != null && user.Password == password)
				{
					user.LastLoginDate = DateTime.Now;
					dataAccess.Update(user);
					return true;
				}
				return false;
			}
		}
	}
}
